# -*- coding:utf8 -*-
import json
import traceback
import os
import typing
import ddddocr
from scrapy import Request, FormRequest
from squirrel_core.commons.utils.tools import calc_str_md5, upload_file
from squirrel_core.frame.spider_makaka import MakakaSpider

file_path = os.environ.get("FILE_PATH", "/")


class mararun_score(MakakaSpider):
    name = "mararun_score"
    serialNumber = ""
    url = "https://saas-user-gw.mararun.com/v1/captcha/code"
    header = {
        "Host": "saas-user-gw.mararun.com",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
        "Content-Type": "application/json",
        "Accept": "application/json, text/plain, */*"
    }
    retry_time = 3
    match_dict = {
        "2025沈阳马拉松": "8379122095068653",
        "2025蒙牛成都马拉松": "8264176489334086",
        "2025天津马拉松": "8377244456303104",
        "2025中国银行北京马拉松": "8315065509895961",
        "2025遂宁观音湖马拉松": "8454673774509280"
    }
    match_id = ""

    def get_ext_requests_or_urls(self, data=None):
        if data and isinstance(data, str):
            data = json.loads(data)
        if data and isinstance(data, typing.MutableMapping):
            self.serialNumber = data.get("serialNumber", "")
            race_id = data.get("spider_config", {}).get("race_id", "")
            user_id = data.get("spider_config", {}).get("user_id", "")
            race_no = data.get("spider_config", {}).get("race_no", "")
            card_num = data.get("spider_config", {}).get("card_num", "")
            user_name = data.get("spider_config", {}).get("user_name", "")
            race_name = data.get("spider_config", {}).get("race_name", "").replace(" ", "")
            if not race_name and not card_num:
                self.logger.info("race_name和card_num必须存在")
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 101, "message": "race_name和card_num必须存在"})
                self.close_after_idle = True
                self.force_to_close_spider = True
            else:
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 100, "message": "任务启动成功"})
                if "2025沈阳马拉松" in race_name:
                    race_name = "2025沈阳马拉松"
                self.match_id = self.match_dict.get(race_name, "")
                yield Request(url=self.url, callback=self.parse, dont_filter=True, errback=self.err_parse,
                              headers={"Accept": "application/json, text/plain, */*"},
                              meta={"race_id": race_id, "user_id": user_id, "card_num": card_num,
                                    "user_name": user_name, "race_name": race_name})

    def parse(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        card_num = response.meta.get("card_num", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        try:
            self.logger.info(f"开始获取沈阳马拉松的sessionid和验证码链接")
            img_url = json.loads(response.text).get("image", "")
            session_id = json.loads(response.text).get("sessionID", "")
            yield Request(img_url, callback=self.parse_img, errback=self.err_parse, dont_filter=True,
                          meta={"race_id": race_id, "user_id": user_id, "card_num": card_num,
                                "race_name": race_name, "user_name": user_name, "session_id": session_id})
        except Exception:
            self.logger.info(f"获取沈阳马拉松的sessionid和验证码链接错误：{traceback.format_exc()}")

    def parse_img(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        card_num = response.meta.get("card_num", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        session_id = response.meta.get("session_id", "")
        try:
            self.logger.info(f"开始打码")
            ocr = ddddocr.DdddOcr(beta=True)
            yzm = ocr.classification(response.body)
            score_url = f"https://saas-user-gw.mararun.com/v1/score/search?matchID={self.match_id}&IDCard={card_num}&sessionID={session_id}&code={yzm}"
            yield Request(score_url, callback=self.parse_score, errback=self.err_parse,
                          headers=self.header, dont_filter=True,
                          meta={"race_id": race_id, "user_id": user_id, "card_num": card_num,
                                "race_name": race_name, "user_name": user_name, "handle_httpstatus_list": [404]})
        except Exception:
            self.logger.info(f"打码错误：{traceback.format_exc()}")

    def parse_score(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        card_num = response.meta.get("card_num", "")
        try:
            self.logger.info(f"开始获取{user_name}成绩")
            content = json.loads(response.text)
            msg = content.get("error", {}).get("message", "")
            result = self.result_item_assembler(response)
            if "验证码" in msg:
                if self.retry_time > 0:
                    self.retry_time -= 1
                    yield Request(url=self.url, callback=self.parse, dont_filter=True, errback=self.err_parse,
                                  headers={"Accept": "application/json, text/plain, */*"},
                                  meta={"race_id": race_id, "user_id": user_id, "card_num": card_num,
                                        "user_name": user_name, "race_name": race_name, "retry_flag": True})
                else:
                    result_dict = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                   "crawlerType": self.name_second, "data": "验证码识别失败，请重试该任务"}
                    result['result_data'] = result_dict
                    yield result
            elif "无成绩" in msg:
                result_dict = {"serialNumber": self.serialNumber, "webType": self.name_first,
                               "crawlerType": self.name_second, "data": "未查到成绩信息"}
                result['result_data'] = result_dict
                yield result
            else:
                score_list = content.get("matchScores", [])
                for match_score in score_list:
                    score_info = match_score.get("matchScore", {})
                    if race_name in score_info.get("matchName", ""):
                        score_section = []
                        data_list = score_info.get("timePointScore", [])
                        for data in data_list:
                            cp_name = data.get("name", "")
                            stop_time = data.get("value", "")
                            cp_length = data.get("englishName", "")
                            score_section.append({"cp_name": cp_name, "score": stop_time, "distance": cp_length})
                        if score_section:
                            score_section[-1]["cp_name"] = "FINISH"
                        sex_rank = {"scoreRank": score_info.get("sexTimeRank", ""), "shotScoreRank": score_info.get("sexGunRank", "")}
                        all_rank = {"scoreRank": score_info.get("timeRank", ""), "shotScoreRank": score_info.get("gunRank", "")}
                        score_data = {"race_name": score_info.get("matchName", ""), "itemName": score_info.get("matchTypeName", ""),
                                      "index": "", "name": user_name, "shotScore": score_info.get("gunScore", ""),
                                      "raceNo": score_info.get("CNO", ""), "pace": score_info.get("timePace", ""),
                                      "distance": "", "score_status": "", "score": score_info.get("timeScore", ""),
                                      "speed": score_info.get("timeMph", ""), "sectionScore": score_section,
                                      "ranks": {"allRanks": all_rank, "sexRanks": sex_rank}, "certImg": ""}
                        cert_url = score_info.get("certificate", "")
                        if cert_url:
                            yield Request(url=cert_url, callback=self.parse_pic, errback=self.err_parse,
                                          meta={"race_id": race_id, "user_id": user_id, "user_name": user_name, "score_data": score_data})
                        else:
                            result = self.result_item_assembler(response)
                            result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                                     "crawlerType": self.name_second, "data": str(score_data)}
                            yield result
        except Exception:
            self.logger.info(f"获取{user_name}成绩错误：{traceback.format_exc()}")

    def parse_pic(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        user_name = response.meta.get("user_name", "")
        score_data = response.meta.get("score_data", {})
        try:
            self.logger.info(f"开始下载{user_name}的证书：{response.url}")
            pic_md5 = calc_str_md5(response.url)
            pic_name = f"{pic_md5}.jpg"
            dir_path = os.path.join(file_path, "picture", self.name_first)
            if not os.path.exists(dir_path):
                os.makedirs(dir_path)
            save_path = os.path.join(dir_path, pic_name)
            if not os.path.exists(save_path):
                with open(save_path, "wb") as f:
                    f.write(response.body)
                upload_path = f"flow/{race_id}/{user_id}/pic/{pic_name}"
                upload_flag = upload_file(save_path, upload_path)
                if upload_flag:
                    self.logger.info(f"{save_path}上传成功：{upload_path}")
                else:
                    self.logger.info(f"{save_path}上传失败：{upload_path}")
                score_data["certImg"] = upload_path
                result = self.result_item_assembler(response)
                result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                         "crawlerType": self.name_second, "data": str(score_data)}
                yield result
        except Exception:
            self.logger.info(f"下载{user_name}证书时出错{response.url}：{traceback.format_exc()}")

    def err_parse(self, failure):
        self.logger.warning(f"请求失败：{failure.request.url},错误原因:{traceback.format_exc()}")

